package com.lj.common_web.aspect;

import com.lj.common.exception.CommonException;
import com.lj.common.utils.RedisUtil;
import com.lj.common_web.annotation.RateLimit;
import com.lj.common_web.utils.ServletUtil;
import jakarta.annotation.Resource;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.stereotype.Component;

/**
 * @author luojing
 * @since 2025/6/3 14:26
 */
@Aspect
@Component
@ConditionalOnClass({RedisUtil.class})
public class RateLimitAspect {

    @Resource
    private RedisUtil redisUtil;

    private static final String RATE_LIMIT_KEY_PREFIX = "RateLimit:";

    @Around("@annotation(rateLimit)")
    public Object rateLimit(ProceedingJoinPoint joinPoint, RateLimit rateLimit) throws Throwable {
        String key = generateKey(joinPoint, rateLimit.model());
        Integer count = redisUtil.get(key);
        if (count == null) {
            count = 0;
        }

        if (count < rateLimit.limit()) {
            if (count == 0) {
                // 这是首次进行设置过期时间
                redisUtil.set(key, count + 1, rateLimit.timeout(), rateLimit.unit());
            } else {
                // 没有达到限制,进行自增1
                redisUtil.incrOrDecr(key, 1);
            }
            return joinPoint.proceed();
        }
        throw new CommonException("操作达到频率限制!");
    }

    private String generateKey(ProceedingJoinPoint joinPoint, RateLimit.Model model) {
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getName();
        String key = RATE_LIMIT_KEY_PREFIX + className + "#" + methodName;
        if (RateLimit.Model.IP == model) {
            String clientIP = ServletUtil.getClientIP(ServletUtil.getRequest());
            return key + ":" + clientIP;
        }
        return key;
    }
}
